<!DOCTYPE html>
<html>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
<head><title>CubicleSoft File Explorer Demo</title></head>
<body>
<style type="text/css">
body { font-family: Verdana, Arial, Helvetica, sans-serif; position: relative; color: #222222; font-size: 1.0em; }

html.embed, html.embed body { padding: 0; margin: 0; }
html.embed p { padding: 0; margin: 0; display: none; }

#filemanager { height: 50vh; max-height: 400px; position: relative; }
html.embed #filemanager { height: 100vh; }
</style>

<p>This is a fully functioning demo of <a href="https://github.com/cubiclesoft/js-fileexplorer">CubicleSoft File Explorer</a>.</p>
<p>Blah</p>
<p>Blah</p>
<p>Blah</p>
<p>Blah</p>

<link rel="stylesheet" type="text/css" href="file-explorer/file-explorer.css">
<script type="text/javascript" src="file-explorer/file-explorer.js"></script>

<div id="filemanager"></div>

<script type="text/javascript">
(function() {
	// Handle iframe demo embed.
	if (window.location.href.indexOf('embed=true') > -1)  document.documentElement.classList.add('embed');

	// Back to regularly scheduled program.
	var elem = document.getElementById('filemanager');

	// Random folders and filenames.
	var testdiropts = [
		{ name: 'Test Folder', type: 'folder', id: 'folder1', hash: 'folder1' },
		{ name: 'Test Folder 2', type: 'folder', id: 'folder2', hash: 'folder2' },
		{ name: 'Test Folder 3', type: 'folder', id: 'folder3', hash: 'folder3' },
		{ name: 'Test Folder 4', type: 'folder', id: 'folder4', hash: 'folder4' },
		{ name: 'Test Folder 5', type: 'folder', id: 'folder5', hash: 'folder5' },
	];

	var testfileopts = [
		{ name: 'Really_long_file_name_that_is_really,_really,_really,_long.xlsx', type: 'file', id: 'file1', hash: 'file1', 'size': 50000, tooltip: 'Last modified: Today\nCool!', overlay: 'custom_fileexplorer_overlay_lock' },
		{ name: 'Another file.txt', type: 'file', id: 'file2', hash: 'file2' },
		{ name: 'Another file.mp3', type: 'file', id: 'file3', hash: 'file3', tooltip: 'Amazing!!!' },
		{ name: 'Test_download_image.jpg', type: 'file', id: 'file4', hash: 'file4', thumb: true },
		{ name: 'Really long file name that is really, really, really, long.png', type: 'file', id: 'file5', hash: 'file5', overlay: 'custom_fileexplorer_overlay_lock', thumb: true },
	];

	// Random thumbnail URLs for the demo.
	var imageurlopts = [
		'https://picsum.photos/{0}/{1}',
		'https://source.unsplash.com/{0}x{1}',
		'https://placebear.com/{0}/{1}',
		'https://placekitten.com/{0}/{1}',
		'https://placekeanu.com/{0}/{1}',
		'https://baconmockup.com/{0}/{1}/'
	];

	var FormatStr = function(format) {
		var args = Array.prototype.slice.call(arguments, 1);

		return format.replace(/{(\d+)}/g, function(match, number) {
			return (typeof args[number] != 'undefined' ? args[number] : match);
		});
	};

	var GetRandomImageURL = function() {
		var url = imageurlopts[Math.floor(Math.random() * imageurlopts.length)];

		url = FormatStr(url, Math.floor(Math.random() * 300) + 200, Math.floor(Math.random() * 300) + 200);

		return url;
	};

	var options = {
		// This allows drag-and-drop and cut/copy/paste to work between windows of the live demo.
		// Your application should either define the group uniquely for your application or not at all.
		group: 'demo_test_group',

		capturebrowser: true,

		initpath: [
			[ '', 'Projects (/)', { canmodify: false } ],
			[ '3', '2020-04-18 Transit Map (3)', { canmodify: false } ],
			[ 'data', 'data' ],
			[ 'data', 'data' ],
			[ 'data', 'data' ],
			[ 'data', 'data' ],
			[ 'data', 'data' ],
			[ 'data', 'data' ],
			[ 'data', 'data' ],
			[ 'data', 'data' ],
			[ 'data', 'data' ],
			[ 'data', 'data' ],
			[ 'data', 'data' ],
			[ 'data', 'data' ],
			[ 'data', 'data' ],
			[ 'data', 'data' ],
			[ 'data', 'data' ],
			[ 'data', 'data' ],
			[ 'data', 'data' ],
			[ 'data', 'data' ],
			[ 'data', 'data' ],
			[ 'data', 'data' ],
			[ 'data', 'data' ],
			[ 'data', 'data' ],
			[ 'data', 'data' ],
			[ 'data', 'data' ],
			[ 'data', 'data' ],
			[ 'data', 'data' ],
			[ 'data', 'data' ],
			[ 'data', 'data' ],
			[ 'data', 'data' ],
			[ 'data', 'data' ],
			[ 'data', 'data' ],
			[ 'data', 'data' ],
			[ 'data', 'data' ],
			[ 'data', 'data' ],
			[ 'data', 'data' ],
			[ 'data', 'data' ],
			[ 'data', 'data' ],
			[ 'data', 'data' ],
			[ 'data', 'data' ],
			[ 'data', 'data' ],
			[ 'data', 'data' ],
			[ 'data', 'data' ],
			[ 'data1', 'data1' ],
			[ 'data2', 'data2' ],
			[ 'data3', 'data3' ],
			[ 'data4', 'data4' ],
			[ 'data5', 'data5' ],
		],

		onfocus: function(e) {
console.log('focus');
console.log(e);
		},

		onblur: function(e) {
console.log('blur');
console.log(e);
		},

		// See main documentation for the complete list of keys.
		// The only tool that won't show as a result of a handler being defined is 'item_checkboxes'.
		tools: {
			item_checkboxes: true
		},

		onrefresh: function(folder, required) {
			// Optional:  Ignore non-required refresh requests.  By default, folders are refreshed every 5 minutes so the widget has up-to-date information.
//			if (!required)  return;

			// Maybe notify a connected WebSocket here to watch the folder on the server for changes.
			if (folder === this.GetCurrentFolder())
			{
			}

			// This code randomly generates content for the demo.
			// See the documentation for a better onrefresh implementation.
			var newentries = [];

			for (var x = 0; x < 10; x++)
			{
				var tempdir = Object.assign({}, testdiropts[Math.floor(Math.random() * testdiropts.length)]);

				tempdir.name = x + ' ' + tempdir.name;
				tempdir.id += '_' + x;
				tempdir.hash += '_' + x;

				newentries.push(tempdir);
			}

			for (var x = 0; x < 100; x++)
			{
				var tempfile = Object.assign({}, testfileopts[Math.floor(Math.random() * testfileopts.length)]);

				tempfile.name = x + ' ' + tempfile.name;
				tempfile.id += '_' + x;
				tempfile.hash += '_' + x;
				if (tempfile.thumb)  tempfile.thumb = GetRandomImageURL();

				newentries.push(tempfile);
			}

			newentries.push({ name: 'data1', type: 'folder', id: 'data1', hash: 'data1' });
			newentries.push({ name: 'data10', type: 'folder', id: 'data10', hash: 'data10' });
			newentries.push({ name: 'data2', type: 'folder', id: 'data2', hash: 'data2' });
			newentries.push({ name: 'data3', type: 'folder', id: 'data3', hash: 'data3' });
			newentries.push({ name: 'data4', type: 'folder', id: 'data4', hash: 'data4' });
			newentries.push({ name: 'data5', type: 'folder', id: 'data5', hash: 'data5' });

			if (this.IsMappedFolder(folder))  folder.SetEntries(newentries);
		},

		onrename: function(renamed, folder, entry, newname) {
			// Simulate network delay.
			setTimeout(function() {
				// The entry is a copy of the original, so it is okay to modify any aspect of it, including id.
				// Passing in a completely new entry to the renamed() callback is also okay.
				entry.id = newname;
				entry.name = newname;

				renamed(entry);
			}, 250);
		},

		onopenfile: function(folder, entry) {
console.log(entry);
		},

		onnewfolder: function(created, folder) {
			// Simulate network delay.
			setTimeout(function() {
				var entry = { name: 'New Folder', type: 'folder', id: 'asdfasdffolder123', hash: 'asdfasdffolder123' };

				created(entry);
			}, 250);
		},

		onnewfile: function(created, folder) {
			// Simulate network delay.
			setTimeout(function() {
				var entry = { name: 'New File.txt', type: 'file', id: 'asdfasdffile123', hash: 'asdfasdffile123' };

				created(entry);
			}, 250);
		},

		oninitupload: function(startupload, fileinfo) {
console.log(fileinfo.file);
console.log(JSON.stringify(fileinfo.folder.GetPathIDs()));

			if (fileinfo.type === 'dir')
			{
				// Create a directory.  This type only shows up if the directory is empty.

				// Simulate network delay.
				setTimeout(function() {

					// Passing false as the second parameter to startupload will remove the item from the queue.
					startupload(false);
				}, 250);
			}
			else
			{
				// Simulate network delay.
				setTimeout(function() {
					// Set a URL, headers, and params to send with the file data to the server.
					fileinfo.url = 'filemanager/';

					fileinfo.headers = {
					};

					fileinfo.params = {
						action: 'upload',
						id: 'temp-12345',
						path: JSON.stringify(fileinfo.folder.GetPathIDs()),
						name: fileinfo.fullPath,
						size: fileinfo.file.size,
						xsrftoken: 'asdfasdf'
					};

					fileinfo.fileparam = 'file';

					// Optional:  Send chunked uploads.  Requires the server to know how to put chunks back together.
					fileinfo.chunksize = 1000000;

					// Optional:  Automatic retry count for the file on failure.
					fileinfo.retries = 3;

					// Start the upload.
					startupload(true);
				}, 250);
			}
		},

		// Optional upload handler function to finalize an uploaded file on a server (e.g. move from a temporary directory to the final location).
		onfinishedupload: function(finalize, fileinfo) {
console.log(fileinfo);
			// Simulate network delay.
			setTimeout(function() {
				finalize(true);
			}, 250);
		},

		// Optional upload handler function to receive permanent error notifications.
		onuploaderror: function(fileinfo, e) {
console.log(e);
console.log(fileinfo);
		},

		oninitdownload: function(startdownload, folder, ids, entries) {
			// Simulate network delay.
			setTimeout(function() {
				// Set a URL and params to send with the request to the server.
				var options = {};

				// Optional:  HTTP method to use.
//				options.method = 'POST';

				options.url = 'filemanager/';

				options.params = {
					action: 'download',
					path: JSON.stringify(folder.GetPathIDs()),
					ids: JSON.stringify(ids),
					xsrftoken: 'asdfasdf'
				};

				// Optional:  Control the download via an in-page iframe (default) vs. form only (new tab).
//				options.iframe = false;

				startdownload(options);
			}, 250);
		},

		ondownloadstarted: function(options) {
console.log('started');
console.log(options);
		},

		ondownloaderror: function(options) {
console.log('error');
console.log(options);
		},

		// Calculated information must be fully synchronous (i.e. no AJAX calls).  Chromium only.
		ondownloadurl: function(result, folder, ids, entry) {
			result.name = (ids.length === 1 ? (entry.type === 'file' ? entry.name : entry.name + '.zip') : 'download-' + Date.now() + '.zip');
			result.url = 'http://127.0.0.1/filemanager/?action=download&xsrfdata=asdfasdfasdf&xsrftoken=asdfasdf&path=' + encodeURIComponent(JSON.stringify(folder.GetPathIDs())) + '&ids=' + encodeURIComponent(JSON.stringify(ids));
		},

		oncopy: function(copied, srcpath, srcids, destfolder) {
			// Simulate network delay.
			setTimeout(function() {
				// Fill an array with copied destination folder entries from the server.
				var entries = [];

				copied(true, entries);
			}, 250);
		},

		onmove: function(moved, srcpath, srcids, destfolder) {
			// Simulate network delay.
			setTimeout(function() {
				// Fill an array with moved destination folder entries from the server.
				var entries = [];

				moved(true, entries);
			}, 250);
		},

		ondelete: function(deleted, folder, ids, entries, recycle) {
			// Ask the user if they really want to delete/recycle the items.
			if (!recycle && !confirm('Are you sure you want to permanently delete ' + (entries.length == 1 ? '"' + entries[0].name + '"' : entries.length + ' items') +  '?'))  deleted('Cancelled deletion');
			else
			{
				// Simulate network delay.
				setTimeout(function() {
					deleted(true);
				}, 250);
			}
		},
	};

	var fe = new window.FileExplorer(elem, options);
console.log(fe);

//fe.Focus();

	// Verify that there aren't any leaked globals.
	setTimeout(function() {
		// Create an iframe and put it in the <body>.
		var iframe = document.createElement('iframe');
		document.body.appendChild(iframe);

		// We'll use this to get a "pristine" window object.
		var pristineWindow = iframe.contentWindow.window;

		// Go through every property on `window` and filter it out if
		// the iframe's `window` also has it.
		console.log(Object.keys(window).filter(function(key) {
			return !pristineWindow.hasOwnProperty(key)
		}));

		// Remove the iframe.
		document.body.removeChild(iframe)
	}, 15000);

/*
	// Test destroy.
	setTimeout(function() {
		fe.Destroy();
	}, 20000);
*/
})();
</script>

<p>Blah</p>
<p>Blah</p>
<p>Blah</p>
<p>Blah</p>
<p>Blah</p>
<p>Blah</p>
<p>Blah</p>
<p>Blah</p>
<p>Blah</p>
<p>Blah</p>
<p>Blah</p>
<p>Blah</p>
<p>Blah</p>
<p>Blah</p>
</body>
</html>
